﻿package com.xkrys.security
{
    import com.hurlant.crypto.Crypto;
    import com.hurlant.crypto.symmetric.ICipher;
    import com.hurlant.crypto.symmetric.IVMode;
    import com.hurlant.util.Hex;
    import flash.net.URLLoader;
    import flash.events.Event;
    import flash.events.HTTPStatusEvent;
    import flash.events.IEventDispatcher;
    import flash.events.IOErrorEvent;
    import flash.events.ProgressEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLLoaderDataFormat;
    import flash.net.URLRequest;
    import flash.utils.ByteArray;
	import flash.display.Loader;
	import flash.system.LoaderContext;
    
    public class EncSwfLoader extends Loader
    {
        private var _key:ByteArray = null;
        private var _iv:ByteArray = null;
        private var _cipher:ICipher;
        private var _cipherType:String = "aes256-cbc";
        private var _urlLoader:URLLoader;
        
        public function get hexKey():String
        {
            return Hex.fromArray(_key);
        }
        
        public function set hexKey(key:String):void
        {
            _key = Hex.toArray(key);
            resetCipher();
        }
        
        public function get hexIv():String
        {
            return Hex.fromArray(_iv);
        }
        
        public function set hexIv(iv:String):void
        {
            _iv = Hex.toArray(iv);
            resetIv();
        }
        
        public function get cipherType():String
        {
            return _cipherType;
        }
        
        public function set cipherType(cipherType:String):void
        {
            _cipherType = cipherType;
            resetCipher();
        }
        
        
        public function EncSwfLoader(_hexKey:String,_hexIv:String)
        {
            super();
			hexIv = _hexIv;
			hexKey = _hexKey;
			
         }
         
         protected function resetCipher():void
         {
                if (_cipher != null)
                    _cipher.dispose();
                _cipher = Crypto.getCipher(_cipherType, _key);
                resetIv();
         }
           
          protected function resetIv():void
           {
               var ivCipher:IVMode = _cipher as IVMode;
            if (ivCipher != null) {
                ivCipher.IV = _iv;
            }
           }

          /**
           * Given a valid url to an encrypted swf, loads the swf after decrypting it.
           * 
           * @param url A valid url to an encrypted swf or any other object that SwfLoader accepts
           */
        override public function load(url:URLRequest, context:LoaderContext = null):void
        {
            // process normally if it's not present
            if (url == null) {
                super.load(url);    
                return;
            }
            
            // we assume it's a valid url to an encrypted swf
            _urlLoader = new URLLoader();
            _urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
            
            // this will configure a listener that will decrypt the swf once it
            // has been fully loaded.
            configureListeners(_urlLoader);
            
            // load the encrypted swf
            _urlLoader.load(url);
        }
        
        // private functions
        
        private function configureListeners(dispatcher:IEventDispatcher):void
        {
            dispatcher.addEventListener(Event.COMPLETE, completeHandler);
            dispatcher.addEventListener(Event.OPEN, forwardHandler);
            dispatcher.addEventListener(ProgressEvent.PROGRESS, forwardHandler);
            dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, forwardHandler);
            dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, forwardHandler);
            dispatcher.addEventListener(IOErrorEvent.IO_ERROR, forwardHandler);
        }
        
        private function completeHandler(event:Event):void
        {
            var data:ByteArray = _urlLoader.data;
            trace(data.length);
            // ICipher writes the decrypted data back to the same byte array, so after this
            // call data now contains the decrypted swf.
            _cipher.decrypt(data);
            
            // this will load the swf directly from the decrytped bytearray
			trace(data);
			trace("hihii");
            super.loadBytes(data);
        }
        
        private function forwardHandler(event:Event):void
        {
            dispatchEvent(event);
        }
        
    } // end class
    
} // end package